#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>

#define NPCreater 0
#define NPUser    1
#define NPMode 0666
#define NPRead  O_RDONLY
#define NPWrite O_WRONLY
#define DEFAULT_FDX -1
#define NPReadSize 1024

const std::string ComPath = "./myfifo";


class NamedPipe {
private:
    std::string GetName() {
        if (_who == NPCreater)
            return "Creater";
        else if (_who == NPUser)
            return "User";
        else
            return "None";
    }

    // 以不同的方式打开对应的文件
    int OpenNamedPipe(mode_t mode) {
        int fd = open(_path.c_str(), mode);
        if (fd == -1) {
            std::cout << "open file fail" << " the reason is " << strerror(errno) << std::endl;
        }
        return fd;
    }
public:
    NamedPipe(const std::string& path, size_t who)
        : _path(path), _who(who), _fd(DEFAULT_FDX)
    {
        // 让服务器端读，让客户端写，服务器创建出对应的管道文件
        if (who == NPCreater) {
            int n = mkfifo(_path.c_str(), NPMode);
            if (n < 0) {
                std::cout << "create named pipe fail!" << " the reason is " << strerror(errno) << std::endl;
            }
            _fd = OpenNamedPipe(NPRead);
            std::cout << GetName() << " create the named pipe" << std::endl;

        } else {
            _fd = OpenNamedPipe(NPWrite);   
        }
    }

    int SomeoneUseToRead(std::string* out) {
        char inbuff[NPReadSize];
        int n = read(_fd, inbuff, sizeof(inbuff) - 1);
        if (n == -1) {
            std::cout << "read failed" << " the reason is " << strerror(errno) << std::endl;
        } 
        inbuff[n] = '\0';
        *out = inbuff;
        return n;
    }

    void SomeoneUseForWrite(const std::string& info) {
        int n = write(_fd, info.c_str(), info.size());
        if (n == -1) {
            std::cout << "write failed" << " the reason is " << strerror(errno) << std::endl;
        }
    }

    ~NamedPipe() {
        if (_who == NPCreater) {
            // 让创建者删除对应的管道文件
            int n = unlink(_path.c_str());
            if (n < 0) 
                std::cout << "remove the named pipe fail!" << " the reason is " << strerror(errno) << std::endl;    
        }
        std::cout << GetName() << " unlink the named pipe file " << std::endl;
        if (_fd != DEFAULT_FDX) {
            close(_fd);
        }
    }
private:
    std::string _path;
    size_t _who;
    int _fd;
};